package org.babygo.connect.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.io.File;
import java.util.concurrent.ConcurrentHashMap;

import org.babygo.connect.handler.code.DecodeInHandler;
import org.babygo.connect.handler.code.EncodeOutHandler;
import org.babygo.connect.handler.server.file.ReceiveFileInHandler;
import org.babygo.connect.handler.server.msg.ReciveNewConnectGroupHandler;
import org.babygo.connect.handler.server.msg.ReciveNewConnectHandler;
import org.babygo.connect.handler.server.msg.ServerFileAcceptedboundHandler;
import org.babygo.connect.handler.server.msg.ServerFileSendOutHandler;
import org.babygo.connect.handler.server.msg.ServerConnectInboundHandler;
import org.babygo.connect.protocol.GetAndSendFileRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class NettyService {
	private Logger log = LoggerFactory.getLogger(NettyService.class);

	private int port;
	private EventLoopGroup bossGroup;
	private EventLoopGroup workerGroup;

	private ConcurrentHashMap<String, Channel> clients = new ConcurrentHashMap<String, Channel>();

	public NettyService(int port){
		this.port = port;
	}

	public boolean opernFileServer(){
		ServerBootstrap serverBootstrap = new ServerBootstrap();
		bossGroup = new NioEventLoopGroup();
		workerGroup  = new NioEventLoopGroup();
		serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {

			@Override
			protected void initChannel(SocketChannel ch) throws Exception {
				ch.pipeline().addLast(new ReceiveFileInHandler());
			}
		}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
		try{
			ChannelFuture channelFuture = serverBootstrap.bind(port);
			serverBootstrap.handler(new ReciveNewConnectHandler());
			return channelFuture.sync().isSuccess();
		} catch(Exception e){
			log.error("[服务端]服务开启失败!",e);
			workerGroup.shutdownGracefully();
			bossGroup.shutdownGracefully();
			return false;
		}
	}
	
	public boolean run(){
		ServerBootstrap serverBootstrap = new ServerBootstrap();
		bossGroup = new NioEventLoopGroup();
		workerGroup  = new NioEventLoopGroup();
		serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {

			@Override
			protected void initChannel(SocketChannel ch) throws Exception {
				ch.pipeline().addLast(new EncodeOutHandler());
				ch.pipeline().addLast(new ServerFileSendOutHandler());
				ch.pipeline().addLast(new DecodeInHandler());
				ch.pipeline().addLast(new ServerConnectInboundHandler());
				ch.pipeline().addLast(new ServerFileAcceptedboundHandler());
			}
		}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
		try{
			ChannelFuture channelFuture = serverBootstrap.bind(port);
			serverBootstrap.handler(new ReciveNewConnectGroupHandler());
			return channelFuture.sync().isSuccess();
		} catch(Exception e){
			log.error("[服务端]服务开启失败!",e);
			workerGroup.shutdownGracefully();
			bossGroup.shutdownGracefully();
			return false;
		}
	}

	public void addNewClient(String ip, String port, Channel channel){
		log.info("加入新的连接--" + ip + ":" + port);
		clients.put(ip + ":" + port, channel);
	}

	public Channel getClient(String ip, String port){
		return clients.get(ip + ":" + port);
	}

	public boolean sendFile(String ip, String port, File f){
		Channel channel = getClient(ip, port);
		if (channel!=null){
			log.info("准备发送文件");
			channel.write(new GetAndSendFileRequest(f.getName(), f));
			return true;
		} else{
			log.info("未找到客户端channel" + ip+ ":" + port);
			return false;
		}
	}
	
	public void stop(){
		workerGroup.shutdownGracefully();
		bossGroup.shutdownGracefully();
	}
}